Skip to content

Conversation

@roxblnfk
Copy link
Collaborator

@roxblnfk roxblnfk commented Oct 28, 2025

What was changed

See the documentation below

Checklist

  1. Closes [Feature Request] Environment Configuration #628
  2. How was this tested: added unit tests

Documentation: External Client Configuration Support

Common docs: https://docs.temporal.io/develop/environment-configuration

The PHP SDK now implements the Temporal external client configuration specification, enabling standardized configuration management across development, staging, and production environments.

This feature allows you to:

  • Store client configuration in TOML files with multiple named profiles (note: requires internal/toml package)
  • Override settings via environment variables
  • Switch between environments without code changes
  • Share configuration files across your team

Configuration File

Create a temporal.toml file in your platform-specific configuration directory:

  • Linux/Unix: ~/.config/temporalio/temporal.toml (or $XDG_CONFIG_HOME/temporalio/temporal.toml)
  • macOS: ~/Library/Application Support/temporalio/temporal.toml
  • Windows: %APPDATA%\temporalio\temporal.toml
[profile.development]
address = "localhost:7233"
namespace = "default"

[profile.production]
address = "my-namespace.a1b2c.tmprl.cloud:7233"
namespace = "my-namespace.a1b2c"
api_key = "your-api-key-here"

[profile.production.tls]
client_cert_path = "/path/to/client.pem"
client_key_path = "/path/to/client.pem"

[profile.production.grpc_meta]
custom-header = "custom-value"

Loading Configuration

The configuration system supports multiple loading strategies:

use Temporal\Common\EnvConfig\ConfigClient;

// Load from default location with environment overrides
$config = ConfigClient::load(
    profileName: 'production',  // or use TEMPORAL_PROFILE env var
);

// Access the profile
$profile = $config->getProfile('production');

// Convert to ServiceClient
$client = $profile->toServiceClient();

// Convert to ClientOptions
$options = $profile->toClientOptions();

Environment Variables

All configuration keys can be overridden via environment variables using the TEMPORAL_* prefix:

# Connection settings
export TEMPORAL_ADDRESS="localhost:7233"
export TEMPORAL_NAMESPACE="my-namespace"
export TEMPORAL_API_KEY="my-secret-key"

# Profile selection
export TEMPORAL_PROFILE="production"

# Config file override
export TEMPORAL_CONFIG_FILE="/custom/path/to/config.toml"

# TLS configuration
export TEMPORAL_TLS="true"
export TEMPORAL_TLS_CLIENT_CERT_PATH="/path/to/cert.pem"
export TEMPORAL_TLS_CLIENT_KEY_PATH="/path/to/key.pem"
export TEMPORAL_TLS_SERVER_CA_CERT_PATH="/path/to/ca.pem"
export TEMPORAL_TLS_SERVER_NAME="custom-server"

# gRPC metadata headers
export TEMPORAL_GRPC_META_X_CUSTOM_HEADER="custom-value"
export TEMPORAL_GRPC_META_AUTHORIZATION="Bearer token"

Environment variables take precedence over configuration file values, enabling easy overrides for CI/CD pipelines and containerized deployments.

Configuration Hierarchy

Configuration is loaded with the following precedence (later values override earlier ones):

  1. Profile from TOML file (if file exists at default location or specified via TEMPORAL_CONFIG_FILE)
  2. Environment variable overrides (any TEMPORAL_* variables)
  3. SDK defaults (applied for unspecified values)

Profile Management

Profiles are case-insensitive and support multiple named configurations in a single file:

// Check if profile exists
if ($config->hasProfile('staging')) {
    $profile = $config->getProfile('staging');
}

// Profile names are case-insensitive
$profile = $config->getProfile('Production');  // matches "production"

// Access all profiles
$profiles = $config->profiles;  // array<string, ConfigProfile>

Loading Strategies

Load from file only:

$config = ConfigClient::loadFromToml('/path/to/temporal.toml');

Load from environment only:

$config = ConfigClient::loadFromEnv();

Load with custom EnvProvider (for testing):

use Temporal\Common\EnvConfig\SystemEnvProvider;

$envProvider = new SystemEnvProvider();
$config = ConfigClient::load(
    profileName: 'test',
    configFile: null,
    envProvider: $envProvider,
);

Remote Codec Support

Note

Remote codec configuration is not supported in the PHP SDK, following the same approach as TypeScript, Python, and .NET SDKs.

If you attempt to configure a remote codec either in the TOML file or via environment variables, the SDK will throw a CodecNotSupportedException to prevent silent failures:

# ❌ This will throw an exception
[profile.production.codec]
endpoint = "https://codec.example.com"
auth = "Bearer token"
# ❌ These will also throw an exception
export TEMPORAL_CODEC_ENDPOINT="https://codec.example.com"
export TEMPORAL_CODEC_AUTH="Bearer token"

This explicit error ensures users are aware that codec functionality is not available, rather than silently ignoring the configuration and causing unexpected behavior.

Use Cases

Development to Production:

# Development
TEMPORAL_PROFILE=development php worker.php

# Production
TEMPORAL_PROFILE=production php worker.php

CI/CD Pipelines:

# Override specific settings without modifying config file
export TEMPORAL_ADDRESS="test.temporal.io:7233"
export TEMPORAL_NAMESPACE="ci-testing"
php run-tests.php

Multi-Tenant Applications:

[profile.tenant-a]
address = "tenant-a.tmprl.cloud:7233"
namespace = "tenant-a"
api_key = "key-a"

[profile.tenant-b]
address = "tenant-b.tmprl.cloud:7233"
namespace = "tenant-b"
api_key = "key-b"

@roxblnfk roxblnfk requested a review from wolfy-j as a code owner October 28, 2025 18:18
@vercel
Copy link

vercel bot commented Oct 28, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
php Ready Ready Preview Comment Nov 17, 2025 5:13pm

Copy link

@THardy98 THardy98 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @roxblnfk !

Thanks for opening the PR.

Took a quick look through and it looks like the public interface deviates pretty notably from other implementations, see Typescript.

We have typically offered an interface that allows you to:

  • load a client configuration (e.g. all profiles in a configuration) from TOML file and overridden by env vars if set
  • load a client configuration, but from provided TOML data and overridden by env vars if set
  • convert a client configuration back to its TOML representation (as bytes)
  • load a single profile
  • load a profile and convert it into a representation that can be immediately used by client/connection (for a quick shorthand way to load and configure your client)

I'm requesting changes such that we keep feature parity here and maintain the same interface in the PHP SDK.

I would also keep in mind the control flow, as it differs in the existing implementations as well (i.e. we only throw ProfileNotFound if a profile name was provided by the user, if not, we return an empty profile)

@roxblnfk
Copy link
Collaborator Author

@THardy98 hi. The specification didn't help me understand some mechanics. Could you clarify these questions:

Question 1:

What is the expected behavior if:

  • I override some profile settings via ENV variables
  • I set TEMPORAL_PROFILE="default"
  • When loading the configuration, I explicitly select a different profile via code

Will the ENV variable values override the options of the different profile, even though the profile is not the configured TEMPORAL_PROFILE?
In other words, is it correct to say that ENV variables override options for all profiles, not just the one specified in TEMPORAL_PROFILE?

Question 2:

If I load configuration from both ENV variables and a TOML config file, and then save the loaded
state back to TOML, will the TOML data contain the values that were overridden from ENV?

@THardy98
Copy link

THardy98 commented Nov 19, 2025

Yeah, good questions, I could've clarified this earlier.

Will the ENV variable values override the options of the different profile, even though the profile is not the configured TEMPORAL_PROFILE?

Yes, the order of precedence is:

  1. provided in code
  2. env var
  3. config file

With profile name, if you specify it in code, we will use it. Other env vars should apply on that profile.
If you do not specify a profile name, we will fallback to the TEMPORAL_PROFILE env var.
If you do not specify TEMPORAL_PROFILE we will fallback to the default profile, "default"

This TS code snippet should be a good reference (that file generally should be a good reference).

In other words, is it correct to say that ENV variables override options for all profiles, not just the one specified in TEMPORAL_PROFILE?

Yes :)
Env vars will always be applied against the profile you are loading. If you do not want env vars to apply against your profile, you can always specify the overrideEnvVars option with an empty object.

If I load configuration from both ENV variables and a TOML config file, and then save the loaded
state back to TOML, will the TOML data contain the values that were overridden from ENV?

The TOML data will contain the values of whatever configuration you provide it.
If that is a configuration from a config file + env var overrides, then that will be what the TOML serializer sees.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Environment Configuration

4 participants